/**
 * 
 */
package com.zd.ticketing.service.impl;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayUtil;
import com.zd.common.bean.model.HardwareInfo;
import com.zd.common.bean.model.ScenicSpot;
import com.zd.common.bean.model.ScenicSpotExt;
import com.zd.common.bean.model.ShortQrcode;
import com.zd.common.bean.model.TicketInfo;
import com.zd.common.bean.model.TicketOrder;
import com.zd.common.bean.model.TicketOrderDetail;
import com.zd.common.bean.model.UserIdInfo;
import com.zd.common.bean.model.UserInfo;
import com.zd.common.bean.model.UserReceiveInfo;
import com.zd.common.common.enums.PayStatusEnum;
import com.zd.common.common.enums.PayTypeEnum;
import com.zd.common.common.enums.PrintStatusEnum;
import com.zd.common.common.enums.TicketChannelEnum;
import com.zd.common.common.enums.TicketVerifyTypeEnum;
import com.zd.common.common.enums.UseTicketsStatusEnum;
import com.zd.common.common.enums.UserIdNumberTypeEnum;
import com.zd.common.common.utils.DateTimeUtil;
import com.zd.common.common.utils.JSONUtil;
import com.zd.common.common.utils.LogUtils;
import com.zd.common.common.utils.QrCodeCreateUtil;
import com.zd.common.common.utils.StringUtils;
import com.zd.common.dao.HardwareInfoDao;
import com.zd.common.dao.ScenicSpotExtDao;
import com.zd.common.dao.ShortQrcodeDao;
import com.zd.common.dao.TicketInfoDao;
import com.zd.common.dao.TicketOrderDao;
import com.zd.common.dao.TicketOrderDetailDao;
import com.zd.common.dao.common.BaseDao;
import com.zd.common.dao.common.FindRequestEntity;
import com.zd.common.dao.common.WhereEnum;
import com.zd.common.service.impl.BaseServiceImpl;
import com.zd.ticketing.bean.vo.MyWxPayConfig;
import com.zd.ticketing.bean.vo.ScenicSpotDetailVo;
import com.zd.ticketing.bean.vo.TicketOrderDetailVo;
import com.zd.ticketing.bean.vo.UserIdInfoReqVo;
import com.zd.ticketing.common.utils.WXPayUtils;
import com.zd.ticketing.service.IScenicSpotService;
import com.zd.ticketing.service.ITicketOrderService;
import com.zd.ticketing.service.IUserInfoService;

/**
 * @author lishi
 * @date 2018年11月13日 上午11:13:59
 */
@Service
public class TicketOrderServiceImpl extends BaseServiceImpl<TicketOrder> implements ITicketOrderService {

	@Autowired
	private TicketOrderDao ticketOrderDao;

	@Autowired
	private TicketOrderDetailDao ticketOrderDetailDao;

	@Autowired
	private ScenicSpotExtDao scenicSpotExtDao;

	@Autowired
	private IUserInfoService userInfoService;

	@Autowired
	private IScenicSpotService senicSpotService;
	
	@Autowired
	private IScenicSpotService scenicSpotService;
	
	@Autowired
	private TicketInfoDao ticketInfoDao;
	
	@Autowired
	private HardwareInfoDao  hardwareInfoDao;
	
	@Autowired
	private ShortQrcodeDao shortQrcodeDao;
	 

	@Override
	public BaseDao<TicketOrder> getBaseDao() {
		return ticketOrderDao;
	}

	@Override
	public Map<String, Object> buyTieckts(String payAppid, String openid, String json, String ip) throws Exception {
		/*
		 * 
		 * 1、解析json，得出购票信息（票类型，张数，取票人，游客信息等）
		 * 2、将票订单信息存入t_ticket_order
		 * 3、拆订单，将订单详细信息存入 t_ticket_order_detail
		 * 4、统一下单
		 */
		Map<String, Object> resultMap = userInfoService.analysisTouristJson(json, false);

		String userId = resultMap.get("userId").toString();
		String appId = resultMap.get("appId").toString();

		ScenicSpotDetailVo scenicSpotDetailVo = senicSpotService.getScenicSpotDetail(appId);
		FindRequestEntity findRequestEntity = new FindRequestEntity();
		findRequestEntity.addWhere("scenic_spot_id", WhereEnum.EQ, scenicSpotDetailVo.getId());
		findRequestEntity.addWhere("user_id", WhereEnum.EQ, Integer.valueOf(userId));
		findRequestEntity.addWhere("status", WhereEnum.EQ, PayStatusEnum.To_be_paid.getKey());
		List<TicketOrder> ticketOrders = ticketOrderDao.find(findRequestEntity);
		if (ticketOrders != null && ticketOrders.size() > 0) {
			resultMap.put("status", false);
			resultMap.put("message", "当前有未完成的订单，请及时处理");
			return resultMap;
		}

		TicketInfo ticketInfo = (TicketInfo) resultMap.get("ticketInfo");
		UserReceiveInfo userReceiveInfo = (UserReceiveInfo) resultMap.get("userReceiveInfo");
		@SuppressWarnings("unchecked")
		List<UserIdInfo> userIdInfoList = (List<UserIdInfo>) resultMap.get("userIdInfoList");

		//将票订单信息存入t_ticket_order
		TicketOrder ticketOrder = new TicketOrder();
		ticketOrder.setScenicSpotId(scenicSpotDetailVo.getId());
		ticketOrder.setChannel(TicketChannelEnum.Platform_user.getKey());
		ticketOrder.setUserId(Integer.valueOf(userId));
		ticketOrder.setTicketId(ticketInfo.getId());
		ticketOrder.setTicketNums(userIdInfoList.size());
		ticketOrder.setReceiverName(userReceiveInfo.getName());
		ticketOrder.setReceiverPhone(userReceiveInfo.getPhone());
		ticketOrder.setReceiverIdNumber(userReceiveInfo.getIdNumber());
		ticketOrder.setReceiverCarNo(userReceiveInfo.getCarNo());
		ticketOrder.setPayType(PayTypeEnum.WX_PAY.getKey());
		ticketOrder.setOrderNo(StringUtils.getRandomWithTimestamp(32));
		ticketOrder.setNeedFee(userIdInfoList.size() * ticketInfo.getPrice());
		ticketOrder.setTotalFee(userIdInfoList.size() * ticketInfo.getPrice());
		ticketOrder.setStatus(PayStatusEnum.To_be_paid.getKey());
		ticketOrder.setCreateTime(new Date());
		ticketOrder.setUpdateTime(new Date());
		ticketOrderDao.insert(ticketOrder);

		//拆订单，将订单详细信息存入 t_ticket_order_detail
		String checkCode = "";
		if (ticketInfo.getVerifyType() == TicketVerifyTypeEnum.More_Than_One_Ticket.getKey()) {//判断票的验票方式来生成验证号
			while (true) {
				checkCode = StringUtils.generateNumbers();
				FindRequestEntity findReq = new FindRequestEntity();
				findReq.addWhere("scenic_spot_id", WhereEnum.EQ,scenicSpotDetailVo.getId());
				findReq.addWhere("check_code", WhereEnum.EQ, checkCode);
				List<TicketOrderDetail> ticketOrderDetails = ticketOrderDetailDao.find(findReq);
				if (ticketOrderDetails == null || ticketOrderDetails.size() == 0) {
					break;
				}
			}
		}
		Date entryTime = DateTimeUtil.string2Date(resultMap.get("entryTime").toString(), "yyyy-MM-dd");
		LogUtils.info(entryTime);
		Calendar cal = Calendar.getInstance();
		cal.setTime(entryTime);
		cal.add(Calendar.DATE, ticketInfo.getEffectiveTime());
		LogUtils.info(cal.getTime());
		for (UserIdInfo userIdInfo : userIdInfoList) {//保存每张门票信息
			TicketOrderDetail ticketOrderDetail = new TicketOrderDetail();
			ticketOrderDetail.setOrderId(ticketOrder.getId());
			ticketOrderDetail.setChannel(TicketChannelEnum.Platform_user.getKey());
			ticketOrderDetail.setUserId(ticketOrder.getUserId());
			ticketOrderDetail.setTicketId(ticketOrder.getTicketId());
			ticketOrderDetail.setScenicSpotId(scenicSpotDetailVo.getId());
			ticketOrderDetail.setUserName(userIdInfo.getUserName());
			ticketOrderDetail.setUserPhone(userIdInfo.getPhone());
			ticketOrderDetail.setUserIdType(UserIdNumberTypeEnum.identity.getKey());
			ticketOrderDetail.setUserIdNumber(userIdInfo.getIdNumber());
			FindRequestEntity findReqUser = new FindRequestEntity();
			findReqUser.addWhere("user_id_number", WhereEnum.EQ, userIdInfo.getIdNumber());
			findReqUser.addWhere("user_id_bid", WhereEnum.NE, "NULL");
			List<TicketOrderDetail> ticketOrderDetailList2 = ticketOrderDetailDao.find(findReqUser);
			if(ticketOrderDetailList2 != null && ticketOrderDetailList2.size() > 0){
				ticketOrderDetail.setUserIdBid(ticketOrderDetailList2.get(0).getUserIdBid());
			}
			
			
			ticketOrderDetail.setEntryTime(entryTime);
			ticketOrderDetail.setValidTime(cal.getTime());
			if (ticketInfo.getVerifyType() == TicketVerifyTypeEnum.More_Than_One_Ticket.getKey()) {
				ticketOrderDetail.setCheckCode(checkCode);
			} else {
				while (true) {
					checkCode = StringUtils.generateNumbers();

					FindRequestEntity findReq = new FindRequestEntity();
					findReq.addWhere("scenic_spot_id", WhereEnum.EQ,scenicSpotDetailVo.getId());
					findReq.addWhere("check_code", WhereEnum.EQ, checkCode);
					List<TicketOrderDetail> ticketOrderDetails = ticketOrderDetailDao.find(findReq);
					if (ticketOrderDetails == null || ticketOrderDetails.size() == 0) {
						break;
					}
				}
				ticketOrderDetail.setCheckCode(checkCode);
			}
			ticketOrderDetail.setStatus(UseTicketsStatusEnum.To_be_paid.getKey());
			ticketOrderDetail.setCreateTime(new Date());
			ticketOrderDetail.setUpdateTime(new Date());
			ticketOrderDetailDao.insert(ticketOrderDetail);

		}

		resultMap = new HashMap<>();
		resultMap.put("status", true);
		resultMap.put("responeMap", unifiedOrder(openid, ticketOrder, ip, scenicSpotDetailVo,"JSAPI"));

		LogUtils.info(resultMap);

		return resultMap;
	}

	/**
	 * 调起下单： JSAPI支付返回页面js签名验证的信息； NATIVE支付返回微信扫码支付二维码
	 * @param openId 支付公众号下的openId
	 * @param ticketOrder 订单信息
	 * @param ip 终端IP
	 * @param scenicSpotDetailVo 支付公众号信息
	 * @param tradeType   交易类型	
	 * @return
	 * @throws Exception
	 */
	private Map<String, String> unifiedOrder(String openId, TicketOrder ticketOrder, String ip,
			ScenicSpotDetailVo scenicSpotDetailVo,String tradeType ) throws Exception {
		Map<String, String> responeMap = new HashMap<String, String>();

		Map<String, String> params = new HashMap<String, String>();
		TicketInfo ticketInfo = ticketInfoDao.get(ticketOrder.getTicketId());
		
		params.put("device_info", "WEB");                                                    //设备号    自定义参数，可以为终端设备号(门店号或收银设备ID)，PC网页或公众号内支付可以传"WEB"
		params.put("body", ticketInfo.getName());                                            //商品描述
		params.put("sign_type", WXPayConstants.SignType.MD5.toString());                     //签名类型   签名类型，默认为MD5，支持HMAC-SHA256和MD5。
		params.put("out_trade_no", ticketOrder.getOrderNo());                                //商户系统内部订单号，要求32个字符内，只能是数字、大小写字母_-|*@ ，且在同一个商户号下唯一。详见商户订单号
		params.put("total_fee", ticketOrder.getTotalFee() + "");                             //订单总金额，单位为分
		params.put("spbill_create_ip", ip);                                                  //终端IP   支持IPV4和IPV6两种格式的IP地址。调用微信支付API的机器IP
		params.put("notify_url", "http://test.ticketing.boshukeji.com/pay/wxPayReturn");     //支付完成后接受微信返回的结果的地址
		params.put("trade_type", tradeType);                                                 //trade_type=JSAPI时（即公众号支付），此参数必传，此参数为微信用户在商户对应appid下的唯一标识。
		
		if(!StringUtils.isBank(openId)){
			params.put("openid", openId);                                                    //用户标识     trade_type=JSAPI时（即JSAPI支付），此参数必传，此参数为微信用户在商户对应appid下的唯一标识
		}
		
		LogUtils.info("unifiedOrder.params:" + JSONObject.toJSONString(params));
		MyWxPayConfig myWxPayConfig = new MyWxPayConfig(scenicSpotDetailVo.getPayAppId(),
				scenicSpotDetailVo.getPayMchId(), scenicSpotDetailVo.getPaySecretKey(),
				scenicSpotDetailVo.getPayCertPath());
		WXPay wxPay = new WXPay(myWxPayConfig);
		Map<String, String> resultMap = wxPay.unifiedOrder(params);
		LogUtils.info("unifiedOrder.resultMap:" + JSONObject.toJSONString(resultMap));
		String RETURN_CODE = "return_code";
		String return_code = resultMap.get(RETURN_CODE);
		//return_code :SUCCESS/FAIL 此字段是通信标识，非交易标识，交易是否成功需要查看result_code来判断
		if (return_code.equals(WXPayConstants.FAIL)) {
			responeMap.put("error", "连接服务器失败,请重试");
			return responeMap;
		} else if (return_code.equals(WXPayConstants.SUCCESS)) {
			String result_code = resultMap.get("result_code");
			if (result_code.equals(WXPayConstants.FAIL)) {
				responeMap.put("error", "下单失败，请重试");
				return responeMap;
			} else {
				String prepay_id = resultMap.get("prepay_id");
				Map<String, String> wxPayParams = new HashMap<String, String>();
				wxPayParams.put("appId", scenicSpotDetailVo.getPayAppId());
				wxPayParams.put("timeStamp", System.currentTimeMillis() / 1000 + "");
				wxPayParams.put("nonceStr", WXPayUtil.generateNonceStr());
				wxPayParams.put("package", "prepay_id=" + prepay_id);
				wxPayParams.put("signType", "MD5");
				wxPayParams.put("paySign",
						WXPayUtil.generateSignature(wxPayParams, "fewqfweagarewrjuykikobbfd113r234"));
				LogUtils.debug("wxPayParams:" + JSONObject.toJSONString(wxPayParams));
				wxPayParams.put("packageStr", "prepay_id=" + prepay_id);
				responeMap.put("wxPayParams", JSONObject.toJSONString(wxPayParams));
				responeMap.put("orderNo", ticketOrder.getOrderNo());
				String codeUrl = resultMap.get("code_url");
				responeMap.put("codeUrl", codeUrl);
			}
		}
		return responeMap;
	}

	@Override
	public Map<String, String> modifyTiecktsStatus(String orderNo, String transactionId) throws Exception {
		Map<String, String> resultMap = new HashMap<>();
		FindRequestEntity findReq = new FindRequestEntity();
		findReq.addWhere("order_no", WhereEnum.EQ, orderNo);
		findReq.addWhere("transaction_id", WhereEnum.EQ, transactionId);
		List<TicketOrder> ticketOrderList = ticketOrderDao.find(findReq);
		if (ticketOrderList != null && ticketOrderList.size() > 0) {
			TicketOrder ticketOrder = ticketOrderList.get(0);
			ticketOrder.setStatus(PayStatusEnum.Payment_success.getKey());
			ticketOrder.setUpdateTime(new Date());
			ticketOrderDao.update(ticketOrder);
			findReq = new FindRequestEntity();
			findReq.addWhere("order_id", WhereEnum.EQ, ticketOrder.getId());
			List<TicketOrderDetail> ticketOrderDetailList = ticketOrderDetailDao.find(findReq);
			if (ticketOrderDetailList != null && ticketOrderDetailList.size() > 0) {
				for (TicketOrderDetail ticketOrderDetail : ticketOrderDetailList) {
					ticketOrderDetail.setStatus(UseTicketsStatusEnum.Already_paid.getKey());
					ticketOrderDetail.setUpdateTime(new Date());
					ticketOrderDetailDao.update(ticketOrderDetail);
				}
				resultMap.put("message", "success");
			}
		}
		return resultMap;
	}

	@Override
	public void wxPayReturn(String xmlStr) throws Exception {
		LogUtils.info("xmlStr : " + xmlStr);
		String RETURN_CODE = "return_code";
		String return_code;
		Map<String, String> respData = WXPayUtils.xmlToMap(xmlStr);
		for(String key : respData.keySet()) {
			LogUtils.info(key + " : " + respData.get(key));
		}
		if (respData.containsKey(RETURN_CODE)) {
			return_code = respData.get(RETURN_CODE);
		} else {
			LogUtils.debug(String.format("No `return_code` in XML: %s", xmlStr));
			return;
		}

		if (return_code.equals(WXPayConstants.FAIL)) {
			LogUtils.debug("return_code is FAIL");
			return;
		} else if (return_code.equals(WXPayConstants.SUCCESS)) {
			String outTradeNo = respData.get("out_trade_no");
			FindRequestEntity findReq = new FindRequestEntity();
			findReq.addWhere("order_no", WhereEnum.EQ, outTradeNo);
			List<TicketOrder> ticketOrderList = find(findReq);
			if (ticketOrderList != null & ticketOrderList.size() > 0) {
				TicketOrder ticketOrder = ticketOrderList.get(0);
				ScenicSpotDetailVo scenicSpotDetailVo = getScenicSpotDetail(outTradeNo);
				MyWxPayConfig myWxPayConfig = new MyWxPayConfig(scenicSpotDetailVo.getPayAppId(),
						scenicSpotDetailVo.getPayMchId(), scenicSpotDetailVo.getPaySecretKey(),
						scenicSpotDetailVo.getPayCertPath());
				WXPay wxPay = new WXPay(myWxPayConfig);
				if (wxPay.isResponseSignatureValid(respData)) {
					String tradeType = respData.get("trade_type");
					String bankType = respData.get("bank_type");
					String transactionId = respData.get("transaction_id");
					/*
					 * 修改订单支付成功信息，添加订单流水号
					 */
					ticketOrder.setBankType(bankType);
					ticketOrder.setTradeType(tradeType);
					ticketOrder.setTransactionId(transactionId);
					ticketOrder.setStatus(PayStatusEnum.Payment_success.getKey());
					ticketOrder.setPayTime(new Date());
					ticketOrder.setUpdateTime(new Date());
					ticketOrderDao.update(ticketOrder);

					findReq = new FindRequestEntity();
					findReq.addWhere("order_id", WhereEnum.EQ, ticketOrder.getId());
					List<TicketOrderDetail> ticketOrderDetailList = ticketOrderDetailDao.find(findReq);
					if (ticketOrderDetailList != null && ticketOrderDetailList.size() > 0) {
						for (TicketOrderDetail ticketOrderDetail : ticketOrderDetailList) {//修改门票支付成功信息
							ticketOrderDetail.setStatus(PayStatusEnum.Payment_success.getKey());
							ticketOrderDetail.setUpdateTime(new Date());
							ticketOrderDetailDao.update(ticketOrderDetail);
						}
					}
				}
			} else {
				LogUtils.debug(String.format("Invalid sign value in XML: %s", xmlStr));
				return;
			}
		} else {
			LogUtils.debug(String.format("return_code value %s is invalid in XML: %s", return_code, xmlStr));
			return;
		}

	}

	@Override
	public ScenicSpotDetailVo getScenicSpotDetail(String orderNo) throws Exception {
		FindRequestEntity findReq = new FindRequestEntity();
		findReq.addWhere("order_no", WhereEnum.EQ, orderNo);
		List<TicketOrder> ticketOrderList = find(findReq);
		if (ticketOrderList != null & ticketOrderList.size() > 0) {
			TicketOrder ticketOrder = ticketOrderList.get(0);
			ScenicSpot scenicSpot = senicSpotService.get(ticketOrder.getScenicSpotId());
			if (scenicSpot != null) {
				ScenicSpotDetailVo resultVo = new ScenicSpotDetailVo();
				BeanUtils.copyProperties(scenicSpot, resultVo);

				// 获取扩展信息
				findReq = new FindRequestEntity();
				findReq.addWhere("scenic_spot_id", WhereEnum.EQ, scenicSpot.getId());
				List<ScenicSpotExt> extList = scenicSpotExtDao.find(findReq);
				if (extList != null && extList.size() > 0) {
					ScenicSpotExt ext = extList.get(0);
					BeanUtils.copyProperties(ext, resultVo);
				}
				return resultVo;
			}
		}
		return null;
	}

	@Override
	public List<TicketOrderDetailVo> getTicketOrderDetailList(Integer orderId) throws Exception {
		FindRequestEntity findReq = new FindRequestEntity();
		findReq.addWhere("order_id", WhereEnum.EQ, orderId);
		List<TicketOrderDetail> ticketOrderDetailList = ticketOrderDetailDao.find(findReq);
		return orderDetailToVo(ticketOrderDetailList);
	}
	
	/**
	 * 将数据库游客信息对象，转换为页面展示对象，并找出门票类型信息
	 * @param ticketOrderDetailList
	 * @return
	 * @throws Exception
	 */
	private List<TicketOrderDetailVo> orderDetailToVo(List<TicketOrderDetail> ticketOrderDetailList) throws Exception{
		List<TicketOrderDetailVo> ticketOrderDetailVoList = new ArrayList<>();
		if(ticketOrderDetailList != null && ticketOrderDetailList.size() > 0){
			for (TicketOrderDetail ticketOrderDetail : ticketOrderDetailList) {
				TicketOrderDetailVo ticketOrderDetailVo= new TicketOrderDetailVo();
				BeanUtils.copyProperties(ticketOrderDetail, ticketOrderDetailVo);
				
				ShortQrcode shortQrcode =new ShortQrcode();
				String uuid = StringUtils.getRandomWithTimestamp16();
				shortQrcode.setUuid(uuid);
				shortQrcode.setOrderDetailId(ticketOrderDetail.getId());
				shortQrcode.setScenicSpotId(ticketOrderDetail.getScenicSpotId());
				shortQrcode.setOrderId(ticketOrderDetail.getOrderId());
				shortQrcode.setCheckCode(ticketOrderDetail.getCheckCode());
				shortQrcodeDao.insert(shortQrcode);
				
				ticketOrderDetailVo.setQrCodeStr(shortQrcode.getUuid());
				ticketOrderDetailVo.setQrCode(QrCodeCreateUtil.generalQRCode(ticketOrderDetailVo.getQrCodeStr()));
				
				
				ticketOrderDetailVo.setEntryTimeStr(DateTimeUtil.date2String(ticketOrderDetail.getEntryTime()));
				ticketOrderDetailVo.setValidTimeStr(DateTimeUtil.date2String(ticketOrderDetail.getValidTime()));
				
				TicketInfo ticketInfo = ticketInfoDao.get(ticketOrderDetail.getTicketId());
				ticketOrderDetailVo.setEffectiveNum(ticketInfo.getVerifyType());
				ticketOrderDetailVoList.add(ticketOrderDetailVo);
			}
		}
		return ticketOrderDetailVoList;
	}

	@Override
	public Map<String, String> cancelOrder(Integer orderId) throws Exception {
		Map<String, String> resultMap = new HashMap<>();
		TicketOrder ticketOrder = ticketOrderDao.get(orderId);
		ticketOrder.setStatus(PayStatusEnum.cancel_order.getKey());
		ticketOrder.setUpdateTime(new Date());
		ticketOrderDao.update(ticketOrder);
		resultMap.put("status", "success");
		return resultMap;
	}

	@Override
	public Map<String, String> goDownAgain(Integer orderId ,String ip) throws Exception {
		TicketOrder ticketOrder = ticketOrderDao.get(orderId);
		ticketOrder.setOrderNo(StringUtils.getRandomWithTimestamp(32));
		ticketOrder.setUpdateTime(new Date());
		ticketOrderDao.update(ticketOrder);
		UserInfo userInfo = userInfoService.get(ticketOrder.getUserId());
		ScenicSpotDetailVo scenicSpotDetailVo = scenicSpotService.getScenicSpotDetail(ticketOrder.getScenicSpotId());
		return unifiedOrder(userInfo.getPayOpenid(), ticketOrder, ip, scenicSpotDetailVo,"JSAPI");
	}

	@Override
	public Map<String, Object> getTicketOrderDetailList(String userIdNumber, String checkCode,String deviceNo) throws Exception {
		Map<String, Object> resultMap = new HashMap<>();
		HardwareInfo hardware = new HardwareInfo();
		hardware.setDeviceNo(deviceNo);
		HardwareInfo hardwareInfo = scenicSpotService.getHardwareInfo(hardware);
		resultMap.put("status", false);
		FindRequestEntity findReq = new FindRequestEntity();
		if(!StringUtils.isBank(checkCode)){
			findReq.addWhere("check_code", WhereEnum.EQ, checkCode);
		}
		if(!StringUtils.isBank(userIdNumber)){
			findReq.addWhere("receiver_id_number", WhereEnum.EQ, userIdNumber);
			findReq.addWhere("scenic_spot_id", WhereEnum.EQ, hardwareInfo.getScenicSpotId());
			findReq.addWhere("status", WhereEnum.EQ, PayStatusEnum.Payment_success.getKey());
			List<TicketOrder> ticketOrderList = ticketOrderDao.find(findReq);
			if( ticketOrderList == null || ticketOrderList.size() == 0){
				findReq = new FindRequestEntity();
				findReq.addWhere("user_id_number", WhereEnum.EQ, userIdNumber);
				findReq.addWhere("scenic_spot_id", WhereEnum.EQ, hardwareInfo.getScenicSpotId());
				findReq.addWhere("status", WhereEnum.EQ, UseTicketsStatusEnum.Already_paid.getKey());
				findReq.addWhere("valid_time", WhereEnum.GT, new Date());
				findReq.addWhere("print_status", WhereEnum.EQ, PrintStatusEnum.Non_Printing.getKey());
				List<TicketOrderDetail> ticketOrderDetails = ticketOrderDetailDao.find(findReq);
				if(ticketOrderDetails != null && ticketOrderDetails.size() > 0){
					List<TicketOrderDetailVo> ticketOrderDetailVoList = orderDetailToVoPC(ticketOrderDetails);
					resultMap.put("ticketOrderDetailVoList",  ticketOrderDetailVoList);
					resultMap.put("status", true);
					return resultMap;
				}
				resultMap.put("msg", "没有票务信息");
				return resultMap;
			}
			List<TicketOrderDetailVo> ticketOrderDetailVoList = new ArrayList<>();
			for (TicketOrder ticketOrder : ticketOrderList) {
				if((ticketOrder.getTicketNums() - ticketOrder.getPrintNumber())>0){
					findReq = new FindRequestEntity();
					findReq.addWhere("order_id", WhereEnum.EQ, ticketOrder.getId());
					findReq.addWhere("status", WhereEnum.EQ, UseTicketsStatusEnum.Already_paid.getKey());
					findReq.addWhere("scenic_spot_id", WhereEnum.EQ, hardwareInfo.getScenicSpotId());
					findReq.addWhere("valid_time", WhereEnum.GT, new Date());
					findReq.addWhere("print_status", WhereEnum.EQ, PrintStatusEnum.Non_Printing.getKey());
					List<TicketOrderDetail> ticketOrderDetails = ticketOrderDetailDao.find(findReq);
					List<TicketOrderDetailVo> ticketOrderDetailVos = orderDetailToVoPC(ticketOrderDetails);
					ticketOrderDetailVoList.addAll(ticketOrderDetailVos);
				}
			}
			if(ticketOrderDetailVoList != null && ticketOrderDetailVoList.size() >0){
				resultMap.put("ticketOrderDetailVoList", ticketOrderDetailVoList);
				resultMap.put("status", true);
				return resultMap;
			}
			resultMap.put("msg", "没有票务信息");
			return resultMap;
		}
		findReq.addWhere("status", WhereEnum.EQ, UseTicketsStatusEnum.Already_paid.getKey());
		findReq.addWhere("print_status", WhereEnum.EQ, PrintStatusEnum.Non_Printing.getKey());
		findReq.addWhere("scenic_spot_id", WhereEnum.EQ, hardwareInfo.getScenicSpotId());
		findReq.addWhere("valid_time", WhereEnum.GT, new Date());
		List<TicketOrderDetail> ticketOrderDetails = ticketOrderDetailDao.find(findReq);
		if(ticketOrderDetails != null && ticketOrderDetails.size() > 0){
			findReq = new FindRequestEntity();
			findReq.addWhere("status", WhereEnum.EQ, UseTicketsStatusEnum.Already_paid.getKey());
			findReq.addWhere("print_status", WhereEnum.EQ, PrintStatusEnum.Non_Printing.getKey());
			findReq.addWhere("scenic_spot_id", WhereEnum.EQ, hardwareInfo.getScenicSpotId());
			findReq.addWhere("order_id", WhereEnum.EQ, ticketOrderDetails.get(0).getOrderId());
			findReq.addWhere("valid_time", WhereEnum.GT, new Date());
			List<TicketOrderDetail> ticketOrderDetailsl= ticketOrderDetailDao.find(findReq);
			List<TicketOrderDetailVo> ticketOrderDetailVoList = orderDetailToVoPC(ticketOrderDetailsl);
			resultMap.put("ticketOrderDetailVoList",  ticketOrderDetailVoList);
			resultMap.put("status", true);
			return resultMap;
		}
		resultMap.put("msg", "没有票务信息");
		return resultMap;
	}

	@Override
	public Map<String, String> updatePcprintStatus(Integer orderDetailId) throws Exception {
		Map<String, String>  resultMap = new HashMap<>();
		TicketOrderDetail ticketOrderDetail = ticketOrderDetailDao.get(orderDetailId);
		ticketOrderDetail.setPrintStatus(PrintStatusEnum.Already_Printed.getKey());
		ticketOrderDetail.setPrintTime(new Date());
		ticketOrderDetail.setUpdateTime(new Date());
		ticketOrderDetailDao.update(ticketOrderDetail);
		resultMap.put("status", "status");
		return resultMap;
	}

	@Override
	public Map<String, String> buyTiecktsPC(String userIdInfoList, Integer ticketInfoId, String ip, String deviceNo) throws Exception {
		List< UserIdInfoReqVo> userIdInfos = JSONUtil.jsonToList(userIdInfoList, UserIdInfoReqVo.class);
		UserReceiveInfo userReceiveInfo = new UserReceiveInfo();
		userReceiveInfo.setName(userIdInfos.get(0).getUserName());
		userReceiveInfo.setIdNumber(userIdInfos.get(0).getIdNumber());
		TicketInfo ticketInfo = ticketInfoDao.get(ticketInfoId);
		FindRequestEntity findReq = new FindRequestEntity();
		findReq.addWhere("device_no", WhereEnum.EQ, deviceNo);
		List<HardwareInfo> hardwareInfoList = hardwareInfoDao.find(findReq);
		if(hardwareInfoList != null && hardwareInfoList.size() > 0){
			ScenicSpotDetailVo scenicSpotDetailVo = scenicSpotService.getScenicSpotDetail(hardwareInfoList.get(0).getAppId());
			TicketOrder ticketOrder = savaTicket(userReceiveInfo, userIdInfos, ticketInfo, scenicSpotDetailVo,hardwareInfoList.get(0));
			String codeUrl = unifiedOrder(null, ticketOrder, ip, scenicSpotDetailVo, "NATIVE ").get("codeUrl");
			Map<String, String> resultMap = new HashMap<>();
			resultMap.put("ticketOrderId", ticketOrder.getId().toString());
			resultMap.put("codeUrl", QrCodeCreateUtil.generalQRCode(codeUrl));
			resultMap.put("ticketNums",ticketOrder.getTicketNums() +"");
			resultMap.put("totalFee",ticketOrder.getTotalFee()/100.0+"");
			return resultMap;
		}
		return null;
	}
	
	private TicketOrder savaTicket(UserReceiveInfo userReceiveInfo,List<UserIdInfoReqVo> userIdInfoList,TicketInfo ticketInfo,ScenicSpotDetailVo scenicSpotDetailVo,HardwareInfo hardwareInfo) throws Exception {
		TicketOrder ticketOrder = new TicketOrder();
		ticketOrder.setScenicSpotId(scenicSpotDetailVo.getId());
		ticketOrder.setChannel(TicketChannelEnum.Automatic_Ticket.getKey());
		ticketOrder.setUserId(hardwareInfo.getId());
		ticketOrder.setTicketId(ticketInfo.getId());
		ticketOrder.setTicketNums(userIdInfoList.size());
		ticketOrder.setReceiverName(userReceiveInfo.getName());
		ticketOrder.setReceiverPhone(userReceiveInfo.getPhone());
		ticketOrder.setReceiverIdNumber(userReceiveInfo.getIdNumber());
		ticketOrder.setReceiverCarNo(userReceiveInfo.getCarNo());
		ticketOrder.setPayType(PayTypeEnum.WX_PAY.getKey());
		ticketOrder.setOrderNo(StringUtils.getRandomWithTimestamp(32));
		ticketOrder.setNeedFee(userIdInfoList.size() * ticketInfo.getPrice());
		ticketOrder.setTotalFee(userIdInfoList.size() * ticketInfo.getPrice());
		ticketOrder.setStatus(PayStatusEnum.To_be_paid.getKey());
		ticketOrder.setCreateTime(new Date());
		ticketOrder.setUpdateTime(new Date());
		ticketOrderDao.insert(ticketOrder);

		//拆订单，将订单详细信息存入 t_ticket_order_detail
		String checkCode = "";
		if (ticketInfo.getVerifyType() == TicketVerifyTypeEnum.More_Than_One_Ticket.getKey()) {//判断票的验票方式来生成验证号
			while (true) {
				checkCode = StringUtils.generateNumbers();
				FindRequestEntity findReq = new FindRequestEntity();
				findReq.addWhere("scenic_spot_id", WhereEnum.EQ,scenicSpotDetailVo.getId());
				findReq.addWhere("check_code", WhereEnum.EQ, checkCode);
				List<TicketOrderDetail> ticketOrderDetails = ticketOrderDetailDao.find(findReq);
				if (ticketOrderDetails == null || ticketOrderDetails.size() == 0) {
					break;
				}
			}
		}
		Date entryTime = DateTimeUtil.string2Date(DateTimeUtil.date2String(new Date(), "yyyy-MM-dd"), "yyyy-MM-dd");
		LogUtils.info(entryTime);
		Calendar cal = Calendar.getInstance();
		cal.setTime(entryTime);
		cal.add(Calendar.DATE, ticketInfo.getEffectiveTime());
		LogUtils.info(cal.getTime());
		for (UserIdInfoReqVo userIdInfo : userIdInfoList) {
			TicketOrderDetail ticketOrderDetail = new TicketOrderDetail();
			ticketOrderDetail.setChannel(TicketChannelEnum.Automatic_Ticket.getKey());
			ticketOrderDetail.setScenicSpotId(ticketOrder.getScenicSpotId());
			ticketOrderDetail.setUserId(hardwareInfo.getId());
			ticketOrderDetail.setOrderId(ticketOrder.getId());
			ticketOrderDetail.setTicketId(ticketOrder.getTicketId());
			ticketOrderDetail.setUserName(userIdInfo.getUserName());
			ticketOrderDetail.setUserPhone(userIdInfo.getPhone());
			ticketOrderDetail.setUserIdType(UserIdNumberTypeEnum.identity.getKey());
			ticketOrderDetail.setUserIdNumber(userIdInfo.getIdNumber());
			if(userIdInfo.getBid() == null){
				FindRequestEntity findReq = new FindRequestEntity();
				findReq.addWhere("user_id_number", WhereEnum.EQ, userIdInfo.getIdNumber());
				findReq.addWhere("user_id_bid", WhereEnum.NE, "NULL");
				List<TicketOrderDetail> ticketOrderDetailList2 = ticketOrderDetailDao.find(findReq);
				if(ticketOrderDetailList2 != null && ticketOrderDetailList2.size() > 0){
					ticketOrderDetail.setUserIdBid(ticketOrderDetailList2.get(0).getUserIdBid());
				}
			}else {
				ticketOrderDetail.setUserIdBid(userIdInfo.getBid());
			}
			
			ticketOrderDetail.setEntryTime(entryTime);
			ticketOrderDetail.setValidTime(cal.getTime());
			if (ticketInfo.getVerifyType() == TicketVerifyTypeEnum.More_Than_One_Ticket.getKey()) {
				ticketOrderDetail.setCheckCode(checkCode);
			} else {
				while (true) {
					checkCode = StringUtils.generateNumbers();

					FindRequestEntity findReq = new FindRequestEntity();
					findReq.addWhere("scenic_spot_id", WhereEnum.EQ,scenicSpotDetailVo.getId());
					findReq.addWhere("check_code", WhereEnum.EQ, checkCode);
					List<TicketOrderDetail> ticketOrderDetails = ticketOrderDetailDao.find(findReq);
					if (ticketOrderDetails == null || ticketOrderDetails.size() == 0) {
						break;
					}
				}
				ticketOrderDetail.setCheckCode(checkCode);
			}
			ticketOrderDetail.setStatus(UseTicketsStatusEnum.To_be_paid.getKey());
			ticketOrderDetail.setCreateTime(new Date());
			ticketOrderDetail.setUpdateTime(new Date());
			ticketOrderDetailDao.insert(ticketOrderDetail);

		}
		return ticketOrder;
	}

	@Override
	public Map<String, Object> pollingFindOrder(Integer orderId) throws Exception {
		Map<String, Object> resultMap = new HashMap<>();
		resultMap.put("status", false);
		TicketOrder ticketOrder = ticketOrderDao.get(orderId);
		if(ticketOrder.getStatus() == PayStatusEnum.Payment_success.getKey()){
			resultMap.put("status", true);
			FindRequestEntity findReq = new FindRequestEntity();
			findReq.addWhere("order_id", WhereEnum.EQ, ticketOrder.getId());
			List<TicketOrderDetail> ticketOrderDetailList = ticketOrderDetailDao.find(findReq);
			List<TicketOrderDetailVo> ticketOrderDetailVoList = orderDetailToVoPC(ticketOrderDetailList);
			resultMap.put("ticketOrderDetailVoList", ticketOrderDetailVoList);
		}
		return resultMap;
	}
	
	private List<TicketOrderDetailVo> orderDetailToVoPC(List<TicketOrderDetail> ticketOrderDetailList) throws Exception{
		List<TicketOrderDetailVo> ticketOrderDetailVoList = new ArrayList<>();
		if(ticketOrderDetailList != null && ticketOrderDetailList.size() > 0){
			for (TicketOrderDetail ticketOrderDetail : ticketOrderDetailList) {
				TicketOrderDetailVo ticketOrderDetailVo= new TicketOrderDetailVo();
				BeanUtils.copyProperties(ticketOrderDetail, ticketOrderDetailVo);
				
				
				ShortQrcode shortQrcode =new ShortQrcode();
				String uuid = StringUtils.getRandomWithTimestamp16();
				shortQrcode.setUuid(uuid);
				shortQrcode.setOrderDetailId(ticketOrderDetail.getId());
				shortQrcode.setScenicSpotId(ticketOrderDetail.getScenicSpotId());
				shortQrcode.setOrderId(ticketOrderDetail.getOrderId());
				shortQrcode.setCheckCode(ticketOrderDetail.getCheckCode());
				shortQrcodeDao.insert(shortQrcode);
				
				ticketOrderDetailVo.setQrCodeStr(shortQrcode.getUuid());
				ticketOrderDetailVo.setQrCode(QrCodeCreateUtil.generalQRCode(ticketOrderDetailVo.getQrCodeStr()));
				
				
				ticketOrderDetailVo.setEntryTimeStr(DateTimeUtil.date2String(ticketOrderDetail.getEntryTime()));
				ticketOrderDetailVo.setValidTimeStr(DateTimeUtil.date2String(ticketOrderDetail.getValidTime()));
				
				TicketInfo ticketInfo = ticketInfoDao.get(ticketOrderDetail.getTicketId());
				ticketOrderDetailVo.setPrices(ticketInfo.getPrice(), ticketInfo.getChildRate());
				ticketOrderDetailVo.setEffectiveNum(ticketInfo.getVerifyType());
				ticketOrderDetailVoList.add(ticketOrderDetailVo);
			}
		}
		return ticketOrderDetailVoList;
	}

	@Override
	public Map<String, Object> getTicket(Integer orderDetailId) throws Exception {
		Map<String, Object> resultMap = new HashMap<>();
		TicketOrderDetail ticketOrderDetail = ticketOrderDetailDao.get(orderDetailId);
		TicketOrderDetailVo ticketOrderDetailVo= new TicketOrderDetailVo();
		BeanUtils.copyProperties(ticketOrderDetail, ticketOrderDetailVo);
		
		ShortQrcode shortQrcode =new ShortQrcode();
		String uuid = StringUtils.getRandomWithTimestamp16();
		shortQrcode.setUuid(uuid);
		shortQrcode.setOrderDetailId(ticketOrderDetail.getId());
		shortQrcode.setScenicSpotId(ticketOrderDetail.getScenicSpotId());
		shortQrcode.setOrderId(ticketOrderDetail.getOrderId());
		shortQrcode.setCheckCode(ticketOrderDetail.getCheckCode());
		shortQrcodeDao.insert(shortQrcode);
		
		ticketOrderDetailVo.setQrCodeStr(shortQrcode.getUuid());
		ticketOrderDetailVo.setQrCode(QrCodeCreateUtil.generalQRCode(ticketOrderDetailVo.getQrCodeStr()));
		ticketOrderDetailVo.setEntryTimeStr(DateTimeUtil.date2String(ticketOrderDetail.getEntryTime()));
		ticketOrderDetailVo.setValidTimeStr(DateTimeUtil.date2String(ticketOrderDetail.getValidTime()));
		
		TicketInfo ticketInfo = ticketInfoDao.get(ticketOrderDetail.getTicketId());
		ticketOrderDetailVo.setPrices(ticketInfo.getPrice(), ticketInfo.getChildRate());
		ticketOrderDetailVo.setEffectiveNum(ticketInfo.getVerifyType());
		resultMap.put("ticketOrderDetailVo", ticketOrderDetailVo);
		return resultMap;
	}

	@Override
	public Map<String, Object> getCheckCode(String uuid, String deviceNo) throws Exception {
		Map<String, Object> resultMap = new HashMap<>();
		FindRequestEntity findReq = new FindRequestEntity();
		findReq.addWhere("device_no", WhereEnum.EQ, deviceNo);
		List<HardwareInfo> hardwareInfoList = hardwareInfoDao.find(findReq);
		if(hardwareInfoList != null && hardwareInfoList.size()  > 0){
			findReq = new FindRequestEntity();
			findReq.addWhere("uuid", WhereEnum.EQ, uuid);
			findReq.addWhere("scenic_spot_id", WhereEnum.EQ, hardwareInfoList.get(0).getScenicSpotId());
			List<ShortQrcode> shortQrcodeList = shortQrcodeDao.find(findReq);
			if(shortQrcodeList != null && shortQrcodeList.size() > 0){
				resultMap.put("shortQrcode", shortQrcodeList.get(0));
				resultMap.put("result", true);
			}
		}
		return resultMap;
	}
}
